﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace HF.Test
{
    /// <summary>
    /// 测试 <see cref="HExpr.Property.Reader"/> 属性读取
    /// </summary>
    public static class TestRead
    {
        static long GetTick(Action action)
        {
            var t = Stopwatch.StartNew();
            for (int i = 0; i < 1000000; i++)
            {
                action();
            }
            t.Stop();
            var result = t.ElapsedMilliseconds;
            return result;
        }

        /// <summary>
        /// 读取对象属性
        /// </summary>
        public static long[] ReadClassProperty()
        {
            var pro = typeof(ClassObj).GetProperty(nameof(ClassObj.Name));

            HExpr.Property.Reader.Complice(typeof(ClassObj), pro.Name, out var fun, out var fast);
            var fastRead = fast as Func<ClassObj, string>;

            var obj = new ClassObj() { Name = "结构体属性" };
            var result = new long[] {
                GetTick(() => { var value = obj.Name; }),
                GetTick(() => { var value = fastRead(obj);}),
                GetTick(() => { var value = fun(obj); }),
                GetTick(() => { var value = pro.GetValue(obj);}),
            };

            return result;
        }

        /// <summary>
        /// 读取结构体属性
        /// </summary>
        public static long[] ReadStructProperty()
        {
            var pro = typeof(StructObj).GetProperty(nameof(StructObj.Name));

            HExpr.Property.Reader.Complice(typeof(StructObj), pro.Name, out var fun, out var fast);
            var fastRead = fast as HExpr.FuncRef<StructObj, string>;

            object obj = new StructObj() { Name = "结构体属性" };
            StructObj test = new StructObj() { Name = "结构体属性" };

            var result = new long[] {
                GetTick(() => { var value = test.Name; }),
                GetTick(() => { var value = fastRead(ref test);}),
                GetTick(() => { var value = fun(obj); }),
                GetTick(() => { var value = pro.GetValue(obj);}),
            };

            return result;
        }

        /// <summary>
        /// 读取结构体字段
        /// </summary>
        public static long[] ReadStructField()
        {
            var field = typeof(StructObj).GetField(nameof(StructObj.Address));
            HExpr.Property.Reader.Complice(typeof(StructObj), field.Name, out var fun, out var fast);
            var obj = new StructObj() { Address = "字段" };
            var test = new StructObj() { Address = "字段" };

            var fastRead = fast as HExpr.FuncRef<StructObj, string>;

            var result = new long[] {
                GetTick(() => { var value = test.Address; }),
                GetTick(() => { var value = fastRead(ref test);}),
                GetTick(() => { var value = fun(obj); }),
                GetTick(() => { var value = field.GetValue(obj);}),
            };

            return result;
        }

        /// <summary>
        /// 读取结构体字段
        /// </summary>
        public static long[] ReadClassField()
        {
            var field = typeof(ClassObj).GetField(nameof(ClassObj.Address));
            HExpr.Property.Reader.Complice(typeof(ClassObj), field.Name, out var fun, out var fast);
            var fastRead = fast as Func<ClassObj, string>;

            var obj = new ClassObj() { Address = "字段" };
            var result = new long[] {
                GetTick(() => { var value = obj.Name; }),
                GetTick(() => { var value = fastRead(obj);}),
                GetTick(() => { var value = fun(obj); }),
                GetTick(() => { var value = field.GetValue(obj);}),
            };
            return result;
        }

        /// <summary>
        /// 读取类索引属性
        /// </summary>
        public static long[] ReadClassIndexProperty()
        {
            var paramTypes = new Type[] { typeof(int), typeof(string) };
            const BindingFlags C_BF = BindingFlags.Public | BindingFlags.Instance;
            var pro = typeof(ClassObj).GetProperties(C_BF)
                .FirstOrDefault(v => v.Name == "Item");
            HExpr.Property.Reader.Complice(typeof(ClassObj), paramTypes, out var fun, out var fast);
            var fastRead = fast as Func<ClassObj, int, string, int>;
            var obj = new ClassObj();
            var parms = new object[] { 1, "1" };
            var result = new long[] {
                GetTick(() => { var value = obj[1,"1"]; }),
                GetTick(() => { var value = fastRead(obj,1,"1");}),
                GetTick(() => { var value = fun(obj, parms); }),
                GetTick(() => { var value = pro.GetValue(obj, parms);}),
            };
            return result;
        }

        /// <summary>
        /// 读取类索引属性
        /// </summary>
        public static long[] ReadStructIndexProperty()
        {
            var paramTypes = new Type[] { typeof(int), typeof(string) };
            const BindingFlags C_BF = BindingFlags.Public | BindingFlags.Instance;
            var pro = typeof(StructObj).GetProperties(C_BF)
                .FirstOrDefault(v => v.Name == "Item");

            HExpr.Property.Reader.Complice(typeof(StructObj), paramTypes, out var fun, out var fast);
            var fastRead = fast as HExpr.FuncRef<StructObj, int, string, int>;
            var parms = new object[] { 1, "1" };
            object obj = new StructObj();
            StructObj test = new StructObj();
            var result = new long[] {
                GetTick(() => { var value = test[1,"1"]; }),
                GetTick(() => { var value = fastRead(ref test,1,"1");}),
                GetTick(() => { var value = fun(obj, parms); }),
                GetTick(() => { var value = pro.GetValue(obj, parms);}),
            };
            return result;
        }
    }
}
